package com.alibaba.citrus.cr.mn.order.center.facade.function.common;

import com.alibaba.citrus.cr.common.util.ThreadPoolUtil;
import com.alibaba.citrus.cr.mn.order.center.common.SetOrderTag;
import com.alibaba.citrus.cr.mn.order.center.common.util.StopWatchUtils;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.BaseDataServiceAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.CustomerSaleScopeAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.function.dataobject.AtomOrderDO;
import com.alibaba.citrus.cr.mn.order.center.facade.repository.AtomOrderQueryRepository;
import com.alibaba.citrus.cr.mn.order.center.facade.repository.AtomOrderRepository;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.epoch.app.bcorder.service.BaseDataService;
import com.epoch.app.bcorder.service.BcOrderService;
import com.epoch.app.bcorder.service.UnifiedInventoryService;
import com.epoch.app.crb2btradecenter.domain.order.dto.QueryByOrderNosV2Request;
import com.epoch.app.crb2btradecenter.domain.order.model.Order;
import com.epoch.app.crplatformenhance.api.organizationquery.service.OrganizationQueryService;
import com.epoch.app.mnordercenter.model.dto.SalesOrderAtomCreateResponse;
import com.epoch.app.mnordercenter.orderbaserequest.OrderAtomCreateResponse;
import com.epoch.app.mnordercenter.orderbaserequest.OrderLineAtomCreateResponse;
import com.google.common.collect.Lists;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * Chen.mu
 * 2023/5/11
 **/
@SuppressWarnings("ALL")
public abstract class AbstractOrderAtomCreateService {
    private static final Log log = Log.getLogger(AbstractOrderAtomCreateService.class);

    @Resource
    private AtomOrderQueryRepository atomOrderQueryRepository;
    @Resource
    private AtomOrderRepository atomOrderRepository;
    @Resource
    private CustomerSaleScopeAdapter customerSaleScopeAdapter;
    @Resource
    private OrganizationQueryService organizationQueryService;
    @Resource
    private BaseDataServiceAdapter baseDataServiceAdapter;
    @Resource
    private BcOrderService bcOrderService;
    @Resource
    private BaseDataService baseDataService;
    @Resource
    private UnifiedInventoryService unifiedInventoryService;

    public static final String CORE_STOP_WATCH_SEQ = "订单中心原子创建";

    public void idempotentProcess(List<AtomOrderDO> orderWriteList, List<OrderAtomCreateResponse> responseList) {
        StopWatchUtils.start(CORE_STOP_WATCH_SEQ,"idempotentProcess");
        List<Order> orderList = orderWriteList.stream().map(AtomOrderDO::getOrder).collect(Collectors.toList());
        List<String> sourceOrderNos = orderList.stream().map(Order::getSourceOrderNo).distinct().collect(Collectors.toList());
        QueryByOrderNosV2Request nosRequest = new QueryByOrderNosV2Request();
        nosRequest.setFromSys(orderWriteList.get(0).getFromSys());
        nosRequest.setSourceOrderNo(sourceOrderNos);
        nosRequest.setStart(0);
        nosRequest.setLimit(1000);
        Map<String, AtomOrderDO> sourceOrderNoOfOrderMap = atomOrderQueryRepository.queryBySourceOrderNos(nosRequest)
                .stream()
                .collect(Collectors.toMap(p-> {
                    return StringUtils.defaultString(p.getReqNo(), "") + p.getSourceOrderNo();
                }, p -> p, (v1, v2) -> v1));
        log.info("idempotentProcess_DB_SourceOrderNos={}", JSONArray.toJSONString(sourceOrderNoOfOrderMap.keySet()));
        // 根据来源单号进行幂等处理，当来源单号已存在-> 幂等返回已经存在数据 不做更新
        Iterator<AtomOrderDO> iterator = orderWriteList.iterator();
        while (MapUtils.isNotEmpty(sourceOrderNoOfOrderMap) && iterator.hasNext()) {

            AtomOrderDO reqSDO = iterator.next();
            String reqIdempotentKey = StringUtils.defaultString(reqSDO.getReqNo(), "") + reqSDO.getSourceOrderNo();
            AtomOrderDO dbEntity = sourceOrderNoOfOrderMap.get(reqIdempotentKey);

            if (Objects.nonNull(dbEntity)) {
                log.info("idempotentProcess_existed_sourceOrderNo={}", dbEntity.getSourceOrderNo());
                //追加到返回列表，并且不再对该数据进行后续处理
                addIdempotentOrderSuccessResponse(responseList, dbEntity);
                iterator.remove();
            }
        }
        StopWatchUtils.stop();
    }

    public void addIdempotentOrderSuccessResponse(List<OrderAtomCreateResponse> responseList, AtomOrderDO atomOrderDO) {
        List<OrderLineAtomCreateResponse> orderDetails = Optional.ofNullable(atomOrderDO.getOrderLines())
                .orElse(Lists.newArrayList()).stream()
                .map(orderLine -> {
                    OrderLineAtomCreateResponse lineResponse = new OrderLineAtomCreateResponse();

                    lineResponse.setSourceLineNum(orderLine.getSourceLineNum());
                    lineResponse.setLineNum(orderLine.getSerialNumber());
                    //lineResponse.setProductCode(orderLine.getScItemId());

                    return lineResponse;
                })
                .collect(Collectors.toList());

        OrderAtomCreateResponse response = new OrderAtomCreateResponse();
        response.setSalesOrderNo(atomOrderDO.getSalesOrderNo());
        response.setSourceOrderNo(atomOrderDO.getSourceOrderNo());
        response.setOrderDetails(orderDetails);
        responseList.add(response);
    }

    public void submitSaveTransactional(List<AtomOrderDO> orderWriteList, List<OrderAtomCreateResponse> responseList) {
        log.info("SalesOrderAtomCreateService#submitSaveTransactional orderWriteList={}", JSON.toJSONString(orderWriteList));

        StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "submitSaveTransactional");
        CountDownLatch countDownLatch = new CountDownLatch(orderWriteList.size());
        Iterator<AtomOrderDO> iterator = orderWriteList.iterator();
        while (iterator.hasNext()) {
            AtomOrderDO atomOrderDO = iterator.next();
            ThreadPoolUtil.execute(() -> {
                try {
                    StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "saveOrder");
                    SalesOrderAtomCreateResponse response = atomOrderRepository.saveOrder(atomOrderDO);
                    responseList.add(response);
                    if (StringUtils.isNotBlank(response.getErrorCode())) {
                        // 当存在DB异常，则将该单据移除，告知上游保存失败，并不进行同步SAP
                        iterator.remove();
                    }
                } catch (Exception e) {
                    log.error("SalesOrderAtomCreateService#submitSaveTransactional error", e);
                    SalesOrderAtomCreateResponse response = new SalesOrderAtomCreateResponse();
                    response.setSourceOrderNo(atomOrderDO.getOrder().getSourceOrderNo());
                    response.setErrorCode("OC-01-001-01-16-007");
                    switch (getOrderTag()){
                        case SetOrderTag.RETURN:
                            response.setMessage("退货订单批量创建整单失败");
                            break;
                        case SetOrderTag.NORMAL:
                            response.setMessage("销售订单批量创建整单失败");
                            break;
                        case SetOrderTag.EXCHANGE:
                            response.setMessage("换货订单批量创建整单失败");
                            break;
                    }

                    responseList.add(response);
                    iterator.remove();
                } finally {
                    countDownLatch.countDown();
                    StopWatchUtils.stop();
                }
            });
        }

        try {
            countDownLatch.await();
        } catch (Exception e) {
            log.error("SalesOrderAtomCreateService#submitSaveTransactional await error", e);
        }

        StopWatchUtils.stop();
    }

    /*指定单据类型 销售订单Tag：normal，退货订单：return，换货订单：exchange 等等*/
    public abstract String getOrderTag();

    public void printExecConsumerTime() {
        StopWatch currStopWatch = StopWatchUtils.clear();// 移除ThreadLocal中存储对象
        if(Objects.nonNull(currStopWatch)) {
            log.info("AbstractOrderAtomCreateService#batchCreate stopWatch.getTotalTimeSeconds()={}", currStopWatch.getTotalTimeSeconds());
            log.info("AbstractOrderAtomCreateService#batchCreate stopWatch.prettyPrint()={}", currStopWatch.prettyPrint());
        }
    }
}
